#pragma once

#include <queue>

#pragma  warning (disable : 4251)

template<class T>
class __declspec (dllexport) CDispatcher
{
public:
	static CDispatcher<T> & instance()
	{
		static CDispatcher<T> _instance;
		return _instance;
	}
public:
	CDispatcher(void)
		: m_Sensor(0)
	{
		InitializeCriticalSection(&m_Lock);
	}

	~CDispatcher(void)
	{
		EnterCriticalSection(&m_Lock);
		for(unsigned int i = 0; i < 2; i++)
		{
			std::queue<T *> & TQ = m_QueueList[i];
			while(TQ.size())
			{
				T * pVal = TQ.front();
				TQ.pop();
				delete pVal;
			}
		}
		LeaveCriticalSection(&m_Lock);

		DeleteCriticalSection(&m_Lock);
	}
public:
	T * Consume()
	{
		T * ret = 0;
		std::queue<T *> & TQ = m_QueueList[m_Sensor % 2];

		if(TQ.size())
		{
			static unsigned int count = 0;
			count++;

			ret = TQ.front();
			TQ.pop();

			if(count % 1000 == 0 && count != 0)
			{
				printf("Packet Count = %d, Sensor = %d\n", TQ.size(), m_Sensor);
			}
		}

		if(TQ.size() == 0)
		{
			EnterCriticalSection(&m_Lock);
			m_Sensor++;
			LeaveCriticalSection(&m_Lock);
		}

		return ret;
	}

	void Produce(T * val)
	{
		EnterCriticalSection(&m_Lock);
		std::queue<T *> & TQ = m_QueueList[(m_Sensor + 1) % 2];
		TQ.push(val);
		LeaveCriticalSection(&m_Lock);
	}
private:
	std::queue<T *> m_QueueList[2];
	unsigned char	m_Sensor;
	CRITICAL_SECTION m_Lock;
};



#include <queue>

template<class T, unsigned char Size>
class  __declspec (dllexport) CMultiDispatcher
{
public:
	static CMultiDispatcher<T, Size> & instance()
	{
		static CMultiDispatcher<T, Size> _instance;
		return _instance;
	}
public:
	CMultiDispatcher(void)
	{
		memset(m_Sensor, 0, sizeof(m_Sensor));
		for(unsigned int i = 0; i < Size; i++)
		{
			InitializeCriticalSection(&m_Lock[i]);
		}
	}

	~CMultiDispatcher(void)
	{
		for(unsigned int i = 0; i < Size; i++)
		{
			Clear(i);
		}
	}
public:
	T * Consume(unsigned char index)
	{
		T * ret = 0;
		std::queue<T *> & TQ = m_QueueList[2 * index + m_Sensor[index] % 2];

		if(TQ.size())
		{
			ret = TQ.front();
			TQ.pop();
		}

		if(TQ.size() == 0)
		{
			EnterCriticalSection(&m_Lock[index]);
			m_Sensor[index]++;
			LeaveCriticalSection(&m_Lock[index]);
		}

		return ret;
	}

	void Produce(T * val, unsigned char index)
	{
		EnterCriticalSection(&m_Lock[index]);
		std::queue<T *> & TQ = m_QueueList[2 * index + (m_Sensor[index] + 1) % 2];
		TQ.push(val);
		LeaveCriticalSection(&m_Lock[index]);
	}
protected:
	void Clear(unsigned char index)
	{
		EnterCriticalSection(&m_Lock[index]);
		for(unsigned int i = (unsigned int)(2 * index); i < (unsigned int)(2 * index + 2); i++)
		{
			std::queue<T *> & TQ = m_QueueList[i];
			while(TQ.size())
			{
				T * pVal = TQ.front();
				TQ.pop();
				delete pVal;
			}
		}
		LeaveCriticalSection(&m_Lock[index]);

		DeleteCriticalSection(&m_Lock[index]);
	}
private:
	std::queue<T *> m_QueueList[2 * Size];
	unsigned char	m_Sensor[Size];
	CRITICAL_SECTION m_Lock[Size];
};

#pragma  warning (default : 4251)